package ms.maplestory.boot.connection.netty;

import ms.maplestory.boot.ServerConstants;
import ms.maplestory.boot.connection.InPacket;
import ms.maplestory.boot.connection.crypto.Crypto;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j(topic = "[Netty PacketDecoder]")
public class PacketDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext chc, ByteBuf in, List<Object> out) {
        NettyClient c = chc.channel().attr(NettyClient.CLIENT_KEY).get();
        Crypto mCr = chc.channel().attr(NettyClient.CRYPTO_KEY).get();
        if (c != null) {
            byte[] iv = c.getRecvIV();
            if (c.getStoredLength() == -1) {
                if (in.readableBytes() >= 4) {
                    int h = in.readInt();
                    if (!Crypto.checkPacket(h, iv)) {
                        log.error(String.format("[In] | Incorrect packet seq! Dropping client %s.", c.getIP()));
                        c.close();
                        return;
                    }
                    c.setStoredLength(Crypto.getLength(h));
                } else {
                    return;
                }
            }
            if (in.readableBytes() >= c.getStoredLength()) {
                byte[] dec = new byte[c.getStoredLength()];
                in.readBytes(dec);
                c.setStoredLength(-1);
                dec = mCr.crypt(dec, iv);
                c.setRecvIV(Crypto.getNewIv(iv));
                if (ServerConstants.DECRYPT_DATA_ENABLE) dec = mCr.decryptData(dec);
                InPacket inPacket = new InPacket(dec);
                out.add(inPacket);
            }
        }
    }
}
